#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ask_decode.h"
#include "format.h"
#include "utils.h"
#include "libmad/mad.h"

struct ask_decoder ask;
int first;
FILE *in;
u_int8_t inbuf[16384];
int16_t outbuf[1024];

static enum mad_flow input(void *data,struct mad_stream *stream)
{
	u_int8_t *start;
	int remaining,size;
	if(stream->next_frame!=NULL)
	{
		remaining=stream->bufend-stream->next_frame;
		memmove(inbuf,stream->next_frame,remaining);
		start=inbuf+remaining;
		size=sizeof(inbuf)-remaining;
	}
	else
	{
		remaining=0;
		start=inbuf;
		size=sizeof(inbuf);
	}

	int actual=fread(start,1,size,in);
	if(actual<=0) return MAD_FLOW_STOP;

	mad_stream_buffer(stream,inbuf,actual+remaining);

	return MAD_FLOW_CONTINUE;
}

static enum mad_flow header(void *data,struct mad_header const *header)
{
	if(first)
	{
		init_ask_decoder(&ask,header->samplerate);
		first=0;
	}

	return MAD_FLOW_CONTINUE;
}

static int scale(mad_fixed_t sample)
{
	sample+=(1<<(MAD_F_FRACBITS-16)); // round

	if(sample>=MAD_F_ONE) sample=MAD_F_ONE-1; // clip
	else if(sample<-MAD_F_ONE) sample=-MAD_F_ONE;

	return sample>>(MAD_F_FRACBITS+1-16); // quantize
}

static enum mad_flow output(void *data,struct mad_header const *header,struct mad_pcm *pcm)
{
	int bufsize=sizeof(outbuf)/sizeof(outbuf[0]);
	mad_fixed_t const *samples=pcm->samples[0];
	int samples_left=pcm->length;

	while(samples_left)
	{
		int num=bufsize<samples_left?bufsize:samples_left;

		for(int i=0;i<num;i++) outbuf[i]=scale(*samples++);

		provide_ask_input(&ask,outbuf,num);

		samples_left-=num;
	}

	return MAD_FLOW_CONTINUE;
}

static enum mad_flow error(void *data,struct mad_stream *stream,struct mad_frame *frame)
{
	if(stream->error!=0x0101)
	fprintf(stderr,"Decoding error 0x%04x (%s)\n",stream->error,mad_stream_errorstr(stream));

	// return MAD_FLOW_BREAK here to stop decoding (and propagate an error)
	return MAD_FLOW_CONTINUE;
}

int main(int argc,char **argv)
{
	if(argc!=3)
	{
		fprintf(stderr,"Usage: %s input.mpg output.dat\n",argv[0]);
		exit(1);
	}

	in=open_file(argv[1],"rb",stdin,"Couldn't open file \"%s\".\n");

	struct mad_decoder mad;

	first=1;

	mad_decoder_init(&mad,NULL,input,header,NULL /* filter */,output,error,NULL /* message */);
	/*int result=*/mad_decoder_run(&mad,MAD_DECODER_MODE_SYNC);

	mad_decoder_finish(&mad);
	if(in!=stdin) fclose(in);

	if(first||!is_ask_sync_found(&ask))
	{
		fprintf(stderr,"Couldn't find any data in audio file \"%s\".\n",argv[1]);
		exit(4);
	}

	u_int8_t *bytes=ask_data_bytes(&ask);
	int length=ask_data_length(&ask);

	check_errors(bytes,length,argv[1],0);
	fputs(describe_file(bytes,length),stderr);

	FILE *out=open_file(argv[2],"wb",stdout,"Couldn't create file \"%s\".\n");
	fwrite(bytes,1,file_size(bytes,length),out);
	if(out!=stdout) fclose(out);

	destroy_ask_decoder(&ask);
}


